package pe.bf.extranet.dao.impl;

import java.math.BigInteger;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.apache.log4j.Logger;

import oracle.jdbc.OracleTypes;
import pe.bf.base.dao.impl.BaseDAOImpl;
import pe.bf.base.types.OutParameter;
import pe.bf.domain.bean.Empresa;
import pe.bf.domain.bean.Perfil;
import pe.bf.domain.bean.TipoDocumento;
import pe.bf.domain.bean.Usuario;
import pe.bf.domain.exceptions.DomainException;
import pe.bf.extranet.dao.UsuarioDAO;

/**
 * 
 * rfigueroa
 * 
 */
public class UsuarioDAOImpl extends BaseDAOImpl implements UsuarioDAO {

	Logger logger = Logger.getLogger(UsuarioDAOImpl.class);

	private static final String USP_CREAR_USUARIO = "{call PKG_USUARIO.USP_CREAR_USUARIO(?,?,?,?,?,?,?,?,?,?)}";
	private static final String USP_CAMBIO_CLAVE = "{call PKG_USUARIO.USP_CAMBIO_CLAVE(?,?)}";
	private static final String USP_CREA_PERFIL = "{call PKG_USUARIO.USP_CREA_PERFIL(?,?)}";
	private static final String USP_ACTUALIZAR_USUARIO = "{call PKG_USUARIO.USP_ACTUALIZAR_USUARIO(?,?,?,?,?,?,?,?,?)}";
	private static final String USP_ELIMINAR_USUARIO = "{call PKG_USUARIO.USP_ELIMINAR_USUARIO(?)}";
	private static final String USP_BAJA_USUARIO = "{call PKG_USUARIO.USP_BAJA_USUARIO(?)}";
	private static final String USP_ACTIVAR_USUARIO = "{call PKG_USUARIO.USP_ACTIVAR_USUARIO(?)}";
	private static final String USP_LISTAR_USUARIO = "{call PKG_USUARIO.USP_LISTAR_USUARIO(?,?)}";
	private static final String USP_BUSCAR_USUARIO = "{call PKG_USUARIO.USP_BUSCAR_USUARIO(?,?,?,?)}";
	private static final String USP_BUSCAR_USUARIO_ID = "{call PKG_USUARIO.USP_BUSCAR_USUARIO_ID(?,?)}";
	private static final String USP_LISTAR_PERFILES = "{call PKG_USUARIO.USP_LISTAR_PERFILES(?,?)}";

	/**
	 * 
	 * @param dataSource
	 */
	public UsuarioDAOImpl(DataSource dataSource) {
		super(dataSource);
	}

	/**
	 * @param usuario
	 * 
	 *            Este metodo crea usuarios
	 */
	@Override
	public void crearUsuario(Usuario usuario) throws DomainException {
		try {
			long idUsuario = invokeStoreProcedureGetId(USP_CREAR_USUARIO,
					usuario.getEmpresa().getIdEmpresa(), usuario
							.getTipodocumento().getIdTipodocumento(),
					usuario.getNrodocumento(), usuario.getNombres(),
					usuario.getApellidos(), usuario.getTelefono(),
					usuario.getAnexo(), usuario.getEmail(), usuario.getClave(),
					new OutParameter(OracleTypes.NUMBER));

			for (Perfil perfil : (List<Perfil>) usuario.getPerfils()) {
				System.out.println("perfil id " + (perfil.getIdPerfil()));
				registrarPerfiles(idUsuario, perfil.getIdPerfil());
			}

		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	@Override
	public void actualizarClave(Usuario usuario) throws DomainException {
		try {
			invokeStoreProcedure(USP_CAMBIO_CLAVE, usuario.getIdUsuario() + "",
					usuario.getClave());

		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	/**
	 * Este metodo actualiza usuarios
	 * 
	 * @param usuario
	 */
	@Override
	public void actualizarUsuario(Usuario usuario) throws DomainException {
		try {
			invokeStoreProcedure(USP_ACTUALIZAR_USUARIO,
					usuario.getIdUsuario(), usuario.getTipodocumento()
							.getIdTipodocumento(), usuario.getNrodocumento(),
					usuario.getNombres(), usuario.getApellidos(),
					usuario.getTelefono(), usuario.getAnexo(),
					usuario.getEmail(), usuario.getClave());

			for (Perfil perfil : (List<Perfil>) usuario.getPerfils()) {

				registrarPerfiles(usuario.getIdUsuario(), perfil.getIdPerfil());
			}

		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	@Override
	public void registrarPerfiles(long idUsuario, Long idPerfil)
			throws DomainException {
		try {
			invokeStoreProcedure(USP_CREA_PERFIL, idUsuario, idPerfil);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	/**
	 * Este metodo actualiza usuarios
	 * 
	 * @param usuario
	 */
	@Override
	public void actualizarUsuario(List<Usuario> usuario) throws DomainException {
		for (Usuario usu : usuario) {
			actualizarUsuario(usu);
		}
	}

	/**
	 * Este metodo actualiza usuarios
	 * 
	 * @param id
	 */
	@Override
	public void elimiarUsuario(long id) throws DomainException {
		try {
			invokeStoreProcedure(USP_ELIMINAR_USUARIO, id);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	/**
	 * Este metodo da de baja usuarios
	 * 
	 * @param id
	 */
	@Override
	public void bajaUsuario(long id) throws DomainException {
		try {
			invokeStoreProcedure(USP_BAJA_USUARIO, id);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}

	/**
	 * Este metodo da de baja usuarios
	 * 
	 * @param id
	 */
	@Override
	public void activarUsuario(long id) throws DomainException {
		try {
			invokeStoreProcedure(USP_ACTIVAR_USUARIO, id);
		} catch (DomainException e) {
			throw new DomainException(e);
		}
	}
	
	/**
	 * Lista los usuarios por empresa
	 * 
	 * @param idEmpresa
	 */
	@Override
	public List<Usuario> listarUsuarios(BigInteger idEmpresa)
			throws DomainException {

		List<Usuario> usuarioList = null;
		CallableStatement cal = null;
		try {
			cal = invokeStoreProcedureCallable(USP_LISTAR_USUARIO, idEmpresa
					+ "", new OutParameter(OracleTypes.CURSOR));// porque se
																// puso una
																// constante
																// aqui?
			ResultSet resultSet = (ResultSet) cal.getObject(2);
			usuarioList = new ArrayList<Usuario>();
			while (resultSet.next()) {
				Usuario usuario = new Usuario();
				usuario.setIdUsuario(resultSet.getLong("ID_USUARIO"));
				usuario.setTipodocumento(new TipoDocumento(resultSet
						.getLong("ID_TIPODOCUMENTO"), resultSet
						.getString("DESCRIPCION")));
				usuario.setNombres(resultSet.getString("NOMBRES"));
				usuario.setApellidos(resultSet.getString("APELLIDOS"));
				usuario.setNrodocumento(resultSet.getString("NRODOCUMENTO"));
				usuario.setTelefono(resultSet.getString("TELEFONO"));
				usuario.setAnexo(resultSet.getString("ANEXO"));
				usuario.setClave(resultSet.getString("CLAVE"));
				usuario.setEstado(resultSet.getString("ESTADO"));
				usuario.setEmail(resultSet.getString("EMAIL"));
				usuario.setFechacreacion(resultSet.getDate("FECHACREACION"));
				usuario.setUltimoAcceso(resultSet.getDate("ULTIMOACCESO"));
				usuarioList.add(usuario);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);
		} finally {
			try {
				cal.getConnection().close();
				cal.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		return usuarioList;
	}

	@Override
	public Usuario buscarUsuario(Usuario usuarioFiltro) throws DomainException {

		CallableStatement cal = null;
		ResultSet resultSet = null;
		try {

			cal = invokeStoreProcedureCallable(USP_BUSCAR_USUARIO,
					usuarioFiltro.getEmail(), usuarioFiltro.getNrodocumento(),
					usuarioFiltro.getClave(), new OutParameter(
							OracleTypes.CURSOR));
			resultSet = (ResultSet) cal.getObject(4);

			while (resultSet.next()) {
				Usuario usuario = new Usuario();
				usuario.setIdUsuario(resultSet.getLong("ID_USUARIO"));
				Empresa empresa = new Empresa();
				empresa.setIdEmpresa(resultSet.getLong("ID_EMPRESA"));
				empresa.setNombres(resultSet.getString("NOMBRES_EMPRESA"));
				empresa.setRuc(resultSet.getString("RUC_EMPRESA"));
				usuario.setEmpresa(empresa);
				usuario.setTipodocumento(new TipoDocumento(resultSet
						.getLong("ID_TIPODOCUMENTO"), resultSet
						.getString("DESCRIPCION_TD")));
				usuario.setNombres(resultSet.getString("NOMBRES"));
				usuario.setTelefono(resultSet.getString("TELEFONO"));
				usuario.setAnexo(resultSet.getString("ANEXO"));
				usuario.setEmail(resultSet.getString("EMAIL"));
				usuario.setClave(resultSet.getString("CLAVE"));
				usuario.setEstado(resultSet.getString("ESTADO"));
				usuario.setFechacreacion(resultSet.getDate("FECHACREACION"));
				usuario.setPerfilesString(obtenerPerfiles(usuario
						.getIdUsuario()));
				usuario.setUltimoAcceso(resultSet.getDate("ULTIMOACCESO"));
				return usuario;
			}

		} catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);
		} finally {
			try {
				close(resultSet);
				close(cal.getConnection());
				close(cal);
			} catch (SQLException e) {
				e.printStackTrace();
			}

		}
		return null;
	}

	@Override
	public Usuario buscarUsuarioPorId(Usuario usuarioFiltro)
			throws DomainException {

		CallableStatement cal = null;
		try {

			cal = invokeStoreProcedureCallable(USP_BUSCAR_USUARIO_ID,
					usuarioFiltro.getIdUsuario(), new OutParameter(
							OracleTypes.CURSOR));
			ResultSet resultSet = (ResultSet) cal.getObject(2);

			while (resultSet.next()) {
				Usuario usuario = new Usuario();
				usuario.setIdUsuario(resultSet.getLong("ID_USUARIO"));
				Empresa empresa = new Empresa();
				empresa.setIdEmpresa(resultSet.getLong("ID_EMPRESA"));
				empresa.setNombres(resultSet.getString("NOMBRES_EMPRESA"));
				empresa.setRuc(resultSet.getString("RUC_EMPRESA"));
				usuario.setEmpresa(empresa);
				usuario.setTipodocumento(new TipoDocumento(resultSet
						.getLong("ID_TIPODOCUMENTO"), resultSet
						.getString("DESCRIPCION_TD")));
				usuario.setNombres(resultSet.getString("NOMBRES"));
				usuario.setTelefono(resultSet.getString("TELEFONO"));
				usuario.setAnexo(resultSet.getString("ANEXO"));
				usuario.setNrodocumento(resultSet.getString("NRODOCUMENTO"));
				usuario.setEmail(resultSet.getString("EMAIL"));
				usuario.setClave(resultSet.getString("CLAVE"));
				usuario.setEstado(resultSet.getString("ESTADO"));
				usuario.setFechacreacion(resultSet.getDate("FECHACREACION"));
				usuario.setPerfilesString(obtenerPerfiles(usuario
						.getIdUsuario()));
				usuario.setUltimoAcceso(resultSet.getDate("ULTIMOACCESO"));
				return usuario;
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);
		} finally {
			try {
				close(cal.getConnection());
				close(cal);
			} catch (SQLException e) {
				e.printStackTrace();
			}

		}
		return null;
	}

	public String obtenerPerfiles(long usuario) throws DomainException {
		String perfilList = "";
		CallableStatement cal = null;
		try {

			cal = invokeStoreProcedureCallable(USP_LISTAR_PERFILES, usuario
					+ "", new OutParameter(OracleTypes.CURSOR));
			ResultSet resultSet = (ResultSet) cal.getObject(2);
			while (resultSet.next()) {
				Perfil perfil = new Perfil();
				perfil.setIdPerfil(resultSet.getLong("ID_PERFIL"));
				perfil.setDescripcion(resultSet.getString("DESCRIPCION"));
				perfilList = perfilList + resultSet.getLong("ID_PERFIL") + "-";
			}
			return perfilList;

		} catch (SQLException e) {
			e.printStackTrace();
			throw new DomainException(e);

		} finally {
			try {
				cal.getConnection().close();
				cal.close();
			} catch (SQLException e) {

				e.printStackTrace();
			}

		}

	}

	public List<Usuario> obtenerPerfiles(List<Usuario> usuarios)
			throws DomainException {
		List<Usuario> lista = new ArrayList<Usuario>();
		List<Perfil> perfilList = null;
		CallableStatement cal = null;

		for (Usuario usuario : usuarios) {
			try {
				cal = invokeStoreProcedureCallable(USP_LISTAR_PERFILES,
						usuario.getIdUsuario() + "", new OutParameter(
								OracleTypes.CURSOR));
				ResultSet resultSet = (ResultSet) cal.getObject(2);
				perfilList = new ArrayList<Perfil>();
				while (resultSet.next()) {
					Perfil perfil = new Perfil();
					perfil.setIdPerfil(resultSet.getLong("ID_PERFIL"));
					perfil.setDescripcion(resultSet.getString("DESCRIPCION"));
					perfilList.add(perfil);
				}
				usuario.setPerfils(perfilList);
			} catch (SQLException e) {
				throw new DomainException(e);
			} finally {
				try {
					lista.add(usuario);
					cal.getConnection().close();
					cal.close();
				} catch (SQLException e) {					
					e.printStackTrace();
				}
			}
		}
		return lista;
	}

}
